<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>UDP Networking</title>
  </head>

  <body>
    <h1>UDP Networking</h1>

    <h2>Overview</h2>

    <p>Unlike TCP, UDP has no notion of connections. A UDP socket can receive
    datagrams from any server on the network and send datagrams to any host on
    the network. In addition, datagrams may arrive in any order, never arrive at
    all, or be duplicated in transit.</p>

    <p>Since there are no connections, we only use a single object, a protocol,
    for each UDP socket. We then use the reactor to connect this protocol to a
    UDP transport, using the
    <code class="API">twisted.internet.interfaces.IReactorUDP</code>
    reactor API.</p>

    <h2>DatagramProtocol</h2>

    <p>The class where you actually implement the protocol parsing and handling
    will usually be descended
    from <code class="API">twisted.internet.protocol.DatagramProtocol</code> or
    from one of its convenience children. The <code>DatagramProtocol</code>
    class receives datagrams and can send them out over the network. Received
    datagrams include the address they were sent from. When sending datagrams
    the destination address must be specified.</p>

    <p>Here is a simple example:</p>
    <pre class="python">
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class Echo(DatagramProtocol):

    def datagramReceived(self, data, (host, port)):
        print "received %r from %s:%d" % (data, host, port)
        self.transport.write(data, (host, port))

reactor.listenUDP(9999, Echo())
reactor.run()
    </pre>

    <p>As you can see, the protocol is registered with the reactor. This means
    it may be persisted if it's added to an application, and thus it has
    <code class="API"
    base="twisted.internet.protocol.AbstractDatagramProtocol">startProtocol</code>
    and <code class="API"
    base="twisted.internet.protocol.AbstractDatagramProtocol">stopProtocol</code>
    methods that will get called when the protocol is connected and disconnected
    from a UDP socket.</p>

    <p>The protocol's <code class="python">transport</code> attribute will
    implement the <code
    class="API">twisted.internet.interfaces.IUDPTransport</code> interface.
    Notice that the <code class="python">host</code> argument should be an
    IP address, not a hostname. If you only have the hostname use <code
    class="python">reactor.resolve()</code> to resolve the address (see <code
    class="API">twisted.internet.interfaces.IReactorCore.resolve</code>).</p>


    <h2>Connected UDP</h2>

    <p>A connected UDP socket is slightly different from a standard one - it
    can only send and receive datagrams to/from a single address, but this
    does not in any way imply a connection. Datagrams may still arrive in any
    order, and the port on the other side may have no one listening. The
    benefit of the connected UDP socket is that it it <strong>may</strong>
    provide notification of undelivered packages. This depends on many
    factors, almost all of which are out of the control of the application,
    but it still presents certain benefits which occasionally make it
    useful.</p>

    <p>Unlike a regular UDP protocol, we do not need to specify where to send
    datagrams and are not told where they came from since they can only come
    from the address to which the socket is 'connected'.</p>

    <pre class="python">
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class Helloer(DatagramProtocol):

    def startProtocol(self):
        host = "192.168.1.1"
        port = 1234

        self.transport.connect(host, port)
        print "now we can only send to host %s port %d" % (host, port)
        self.transport.write("hello") # no need for address

    def datagramReceived(self, data, (host, port)):
        print "received %r from %s:%d" % (data, host, port)

    # Possibly invoked if there is no server listening on the
    # address to which we are sending.
    def connectionRefused(self):
        print "No one listening"

# 0 means any port, we don't care in this case
reactor.listenUDP(0, Helloer())
reactor.run()
    </pre>

    <p>Note that <code class="python">connect()</code>,
    like <code class="python">write()</code> will only accept IP addresses, not
    unresolved hostnames. To obtain the IP of a hostname
    use <code class="python">reactor.resolve()</code>, e.g.:</p>

  <pre class="python">
from twisted.internet import reactor

def gotIP(ip):
    print "IP of 'example.com' is", ip
    reactor.callLater(3, reactor.stop)

reactor.resolve('example.com').addCallback(gotIP)
reactor.run()
    </pre>

    <p>Connecting to a new address after a previous connection or making a
    connected port unconnected are not currently supported, but likely will be
    in the future.</p>

    <h2>Multicast UDP</h2>

    <p>Multicast allows a process to contact multiple hosts with a single
    packet, without knowing the specific IP address of any of the hosts. This
    is in contrast to normal, or unicast, UDP, where each datagram has a single
    IP as its destination. Multicast datagrams are sent to special multicast
    group addresses (in the IPv4 range 224.0.0.0 to 239.255.255.255), along with
    a corresponding port. In order to receive multicast datagrams, you must
    join that specific group address. However, any UDP socket can send to
    multicast addresses.</p>

    <a href="listings/udp/MulticastServer.py"
    class="py-listing">MulticastServer.py</a>

    <p>As with UDP, with multicast there is no server/client differentiation
    at the protocol level. Our server example is very simple and closely
    resembles a normal <code class="API"
    base="twisted.internet.interfaces.IReactorUDP">listenUDP</code>
    protocol implementation.  The main difference is that instead
    of <code>listenUDP</code>, <code class="API"
    base="twisted.internet.interfaces.IReactorMulticast">listenMulticast</code>
    is called with the port number. The server calls <code class="API"
    base="twisted.internet.interfaces.IMulticastTransport">joinGroup</code> to
    join a multicast group. A <code class="python">DatagramProtocol</code>
    that is listening with multicast and has joined a group can receive
    multicast datagrams, but also unicast datagrams sent directly to its
    address. The server in the example above sends such a unicast message in
    reply to the multicast message it receives from the client.
    </p>

    <a href="listings/udp/MulticastClient.py"
       class="py-listing">MulticastClient.py</a>

    <p>Note that a multicast socket will have a default TTL (time to live) of
    1. That is, datagrams won't traverse more than one router hop, unless a
    higher TTL is set with
     <code class="API"
    base="twisted.internet.interfaces.IMulticastTransport">setTTL</code>. Other
    functionality provided by the multicast transport
    includes <code class="API"
    base="twisted.internet.interfaces.IMulticastTransport">setOutgoingInterface</code>
    and <code class="API"
    base="twisted.internet.interfaces.IMulticastTransport">setLoopbackMode</code>
    -- see <code class="API"
    base="twisted.internet.interfaces">IMulticastTransport</code> for more
    information.</p>

</body>
</html>
